﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AIClient.Configs;

namespace AIClient.Utils
{
    // 日志等级
    public class LogLevel
    {
        public const int Debug   = 0;
        public const int Warning = 1;
        public const int Error   = 2;
    }

    public class LoggerState
    {
        public const int Idle = 0;
        public const int Busy = 1;
    }

    public static class Logger
    {
        private static          int                     _logLevel;
        private static          int                     _state;
        private static readonly ConcurrentQueue<string> _toLogs;
        private static          StreamWriter            _file;

        static Logger()
        {
            _state    = LoggerState.Idle;
            _logLevel = LogLevel.Debug;
            _toLogs   = new ConcurrentQueue<string>();
        }

        // 生成日志
        public static void MakeLogger()
        {
            var cfg = ConfigManager.ServerCfg.LoggerCfg;

            if (!Directory.Exists(cfg.Path))
                Directory.CreateDirectory(cfg.Path);

            var date = DateTime.Now;
            var file =
                new FileStream($"{cfg.Path}{date.Year}-{date.Month}-{date.Day}.log"
                             , FileMode.OpenOrCreate
                             , FileAccess.Write);
            _file           = new StreamWriter(file, Encoding.UTF8);
            Interlocked.Exchange(ref _file, _file);

            ChangeLogLevel(cfg.Level);
        }

        public static void Clear()
        {
            _file.Flush();
            _file.Close();
        }

        public static void LogDebug(string logMessage)
        {
            if (_logLevel > LogLevel.Debug) return;

            Write(logMessage);
        }

        public static void LogWarning(string logMessage)
        {
            if (_logLevel > LogLevel.Warning) return;

            Write(logMessage);
        }

        public static void LogError(string logMessage)
        {
            if (_logLevel > LogLevel.Error) return;

            Write(logMessage);
        }

        public static void ChangeLogLevel(int level)
        {
            Interlocked.Exchange(ref _logLevel, level);
        }

        private static void Write(string logMessage)
        {
            _toLogs.Enqueue($"{DateTime.Now:HH-MM} {logMessage}");

            if (LoggerState.Idle == Interlocked.CompareExchange(ref _state, LoggerState.Busy, LoggerState.Idle))
                Task.Run((Action) WriteProc);

            void WriteProc()
            {
                while (true)
                {
                    if (_toLogs.TryDequeue(out var message))
                        _file.WriteLine(message);

                    if (!_toLogs.IsEmpty) continue;

                    Interlocked.Exchange(ref _state, LoggerState.Idle);
                    break;
                }

                _file.Flush();
            }
        }
    }
}